package com.qianfeng.smartdevice.config;


import com.qianfeng.smartdevice.mapper.MenuMapper;
import com.qianfeng.smartdevice.pojo.Menu;
import com.qianfeng.smartdevice.service.impl.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import java.util.List;

/**
 * Created by jackiechan on 2021/6/18 09:36
 *
 * @author jackiechan
 */
@Configuration
@EnableWebSecurity
@EnableWebMvc
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    private MenuMapper menuMapper;

    @Autowired
    public void setMenuMapper(MenuMapper menuMapper) {
        this.menuMapper = menuMapper;
    }

    private MyUserDetailService userDetailService;

    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public void setPasswordEncoder(BCryptPasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setUserDetailService(MyUserDetailService userDetailService) {
        this.userDetailService = userDetailService;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //如果需要拦截一些地址,最好先在前面设置好权限
        List<Menu> menuList = menuMapper.findAllRealMenus();
        menuList.forEach(menu -> {
            try {
                //设置每个地址需要的权限
//                if (StringUtils.isEmpty(menu.getPerms())) {
//                    return;//在 lambda 表达式的循环中 return标识跳出本次循环,如果想跳出整个循环,扔异常
//                }
                if (!StringUtils.isEmpty(menu.getPerms())) {
                    http.authorizeRequests().antMatchers(menu.getUrl()).hasAuthority(menu.getPerms());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        //http.authorizeRequests().antMatchers("/abc").hasAuthority("123")
        //设置登陆和退出接口地址
        http.authorizeRequests()//
                .anyRequest().authenticated()//任意请求都需要认证,这样配置的原因是因为项目中地址非常多,不确定,所以为了减少安全问题,所有的地址都需要认证,不需要的单独设置即可
                .and().formLogin().loginProcessingUrl("/login").successHandler(
                (req, res, authentication) -> {
                    res.sendRedirect("/index.html");
                }
        ).failureHandler((req, res, authentication) -> {
            req.getSession().removeAttribute("pagelist");
            res.sendRedirect("/login");
        }).permitAll()//设置登陆地址,然后放行
                .and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();
        http.authorizeRequests().antMatchers("/layui/**", "/js/**").permitAll();//这些地址直接放行

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //我们登陆的时候传递的是 admin admin ,数据库中是一个密文,但是这个密文怎么生成的,我们需要告诉 spring security
        auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
//www
//where 在哪设置
//when 上面时候设置
//how 怎么设置进去